'''
Created on April 9, 2011

@author: yc30v1m
'''
import xmlrpclib
import datetime
import base64
from logging import getLogger
from library.AutoLoad import AutoLoad

log = getLogger(__name__)


class Client(object):
    '''
    classdocs
    '''
    _server = ""
    _devKey = ""
    _devKeyName = "devKey"
    _testLinkSignature = "tl"
    testCaseGlueChar = '-'
    _validTestStatusList = {"pass":"p", "fail":"f", "blocked":"b", 
                            "passed":"p", "failed":"f", "Passed":"p", "Falied":"f",
                            "PASS":"p", "FAIL":"f", "P":"p", "F":"f", "Pass":"p", "Fail":"f"}
    
    ProjectName = "PSP"
    TestPlanName = "Test"
    ProjectPrefix = None
    
    _tProjects = None
    _tProject = None
    _tProjectName = None
    _tProjectPrefix = None
    _tProjectId = None
    
    _tTestPlans = None
    _tTestPlanId = None
    
    _tBuilds = None
    _tBuildId = None
    _tLatestBuild = None
    
    _tTestCases = None
    

    def __init__(self, devKey, testProjectName=None, testPlanName=None, testLinkUrl="http://d3162364/testlink/lib/api/xmlrpc.php", testProjectPrefix=False):
        self._devKey = devKey
        start = True
        if testLinkUrl != None:
            self._server = xmlrpclib.ServerProxy(testLinkUrl, transport=None, encoding="UTF-8", verbose=0, allow_none=1, use_datetime=1)
        else:
            start = False
        if testPlanName != None:
            self.TestPlanName = testPlanName
        else:
            start = False
        if testProjectName != None:
            self.ProjectName = testProjectName
        else:
            start = False
        if testProjectPrefix != None:
            # we dont worry if we dont have Project Prefix
            self.ProjectPrefix = testProjectPrefix
        if start:
            self.setupTestlink()
        else:
            log.critical("Unable to Inatilize TestLink Python Client")

        
    def about(self):
        return self._makeXmlRpcCall("about")
    
    def createBuild(self, tBuildName, TestPlanId=None):
        try:
            args = {}
            if TestPlanId == None:
                if self._tTestPlanId != "":
                    args["testplanid"] = self._tTestPlanId
                else:
                    log.critical("TestPlanId not initalized properly")
            else:
                args["testplanid"] = TestPlanId
            args["buildname"] = str(tBuildName)
            args["buildnotes"] = 'Created by Automation Script on ' + str(tBuildName)
            self._makeXmlRpcCall('createBuild', args)
        except:
            log.critical("Unable to create build with name " + str(tBuildName))
    
    def createBuildForToday(self):
        try:
            today = datetime.date.today()
            self.createBuild(str(today))
        except:
            log.critical('Exeception occurred')
    
    def setupTestlink(self):
        today = datetime.date.today()
        #self.getLatestBuildForTestPlan()
        tBuild = self.getTestPlanBuildId(str(today))
        if tBuild != False:
            log.info("we already have Build with todays name and we are all set")
        else:
            self._tBuildId = None
            self._tBuilds = None
            self.createBuildForToday()
            log.info("TestLink client setup Completed")
        self.getTestPlanBuildId(str(today))

        
        
    def createTestCase(self):
        pass
    def createTestProject(self):
        pass
    
    def getTestPlanBuilds(self):
        if self._tBuilds == None:
            if self._tTestPlanId == None:
                self.getProjectTestPlanId()
            data = {"testplanid":self._tTestPlanId}
            self._tBuilds = self._makeXmlRpcCall("getBuildsForTestPlan", data)
        return self._tBuilds
    
    def getTestPlanBuildId(self, BuildName):
        if self._tBuilds == None:
            self.getTestPlanBuilds()
        self._tBuildId = self._idFinder(BuildName, self._tBuilds)
        return self._tBuildId
    
    '''
    Gets the LatestBuild from TL and overrides all the defaults for Build
    Sets up the Build Name & Build Id
    '''    
    def getLatestBuildForTestPlan(self):
        if self._tTestPlanId == None:
            self.getProjectTestPlanId()
        data = {"testplanid":self._tTestPlanId}
        self._tLatestBuild = self._makeXmlRpcCall("getLatestBuildForTestPlan", data)
        return self._tLatestBuild
    
    def getProjects(self):
        self._tProjects = self._makeXmlRpcCall("getProjects")
        log.debug("TestLink retrived projects List : " + str(self._tProjects))
        return self._tProjects 
    
    def getProjectTestPlans(self):
        if self._tProjectId == None:
            self.getProjectId()
        data = {}
        data["testprojectid"] = self._tProjectId
        self._tTestPlans = self._makeXmlRpcCall("getProjectTestPlans", data)
        return self._tTestPlans
    
    def getProjectTestPlanId(self):
        if self._tTestPlanId == None:
            if self._tTestPlans == None:
                self.getProjectTestPlans()
            self._tTestPlanId = self._idFinder(self.TestPlanName, self._tTestPlans)
        return self._tTestPlanId
    
    def getProjectId(self):
        if self._tProjectId == None:
            if self._tProjects == None:
                self.getProjects()
            if self.ProjectPrefix != False:
                self._tProject = self._objectFinder(self.ProjectPrefix, self._tProjects, 'prefix')
                log.debug('temp mesg for Project Prefix = ' + str(self._tProject))
                self._tProjectId = self._finder(self._tProject, 'id')
                self.setupProjectDetails()
            else:
                self._tProject = self._objectFinder(self.ProjectName, self._tProjects, 'name')
                self._tProjectId = self._idFinder(self.ProjectName, self._tProjects)
                self.setupProjectDetails()
        return self._tProjectId
    
    '''
    setups the project and Project perfix 
    also setups the project id & name
    '''
    def setupProjectDetails(self):
        if self._tProjectId == None:
            self.getProjectId()
        self._tProjectPrefix = self._finder(self._tProject, 'prefix')
        self._tProjectName = self._finder(self._tProject, 'name')
    
    def getTestCaseCustomFieldDesignValue(self):
        pass
    
    def getTestCaseIDByName(self):
        pass
    
    def getTestCasesForTestPlan(self, testExecutionType="Automation"):
        if self._tTestPlanId == None:
            self.getProjectTestPlanId()
        data = {}
        data["testplanid"] = self._tTestPlanId
        if testExecutionType == "Automation":
            data["executiontype"] = 2
        else:
            data["executiontype"] = 1
        self._tTestCases = self._makeXmlRpcCall("getTestCasesForTestPlan", data)
        if self._tTestCases == '':
            log.critical('ERROR!!!')
            log.critical('ERROR! There are no TestCases in TestPlan - ')
            log.critical('Please consider looking at TestPlan for Automation / Manual TestCases')
            log.critical('ERROR')
        return self._tTestCases
    
    def getTestCaseIdsForTestPlan(self):
        self._tTestCaseIds = []
        if self._tTestCases == None:
            self.getTestCasesForTestPlan()
        try:
            for tc in self._tTestCases.keys():
                self._tTestCaseIds.append(self._tProjectPrefix + self.testCaseGlueChar + self._tTestCases[tc]['external_id'])
        except Exception, v:
            log.critical('Exception occured ', str(v))
        return self._tTestCaseIds
    
    def getTestCasesForTestSuite(self):
        pass
    def getTestSuitesForTestPlan(self):
        pass
    
    def repeat(self, msg="Hi Tester"):
        args = {}
        args['str'] = msg
        return self._makeXmlRpcCall("repeat", args)
        
    def reportTCResult(self,testCaseId, testResult, notes=""):
        try:
            if testResult in self._validTestStatusList:
                status = self._validTestStatusList[testResult]
            else:
                log.critical("Unable to find proper Test Result status" )
            data = {}
            if self._tBuildId == None:
                self.setupTestlink()
            if self._tBuildId == False:
                self.setupTestlink()
            data["buildid"] = self._tBuildId
            data["testplanid"] = self._tTestPlanId
            data["status"] = status
            data["testcaseexternalid"] = testCaseId
            if notes!="":
                data["notes"] = notes
            return self._makeXmlRpcCall("reportTCResult", data)
        except:
            log.critical("Unable to Report Result in TestLink for TCID: %s: Result: %s: Notes: %s" % (testCaseId, testResult, notes))
            AutoLoad.logExceptionInfo(20)
    
    def sayHello(self):
        pass
    
    def setTestMode(self):
        pass
    
    def updateTestCase(self):
        pass
    
    def getTestCaseAttachments(self,tcid):
        try:
            data = {}
            data["testcaseexternalid"] = tcid
            return self._makeXmlRpcCall("getTestCaseAttachments", data)
        except Exception, v:
            log.critical('Exception occured in getTestCaseAttachments: ' + str(v))
            
    def getAutomationTestCaseFromAttachment(self, tcid):
        tesId = tcid
        attachments = self.getTestCaseAttachments(tcid)
        _ATTACHMENT_NAME_LIKE = 'script'
        latestTimeStamp = ''
        content = ""
        testCase = False
        if len(attachments) > 0:
            pass
        else:
            return testCase
        try:
            for attachment in attachments.keys():
                #if self._hasNeedle(attachments[attachment]['name'], _ATTACHMENT_NAME_LIKE) == True:
                if _ATTACHMENT_NAME_LIKE in attachments[attachment]['name']:
                    tempValue = attachments[attachment]['date_added']
                    if latestTimeStamp == '':
                        latestTimeStamp = tempValue
                    if latestTimeStamp <= tempValue:
                        latestTimeStamp = tempValue
                        content = base64.b64decode(attachments[attachment]['content'])
        except:
            print 'Automation Script Attachments Not found with TestCase : ' + str(tcid)
            AutoLoad.logExceptionInfo()
        try:
            testCase = False
            attachmentClass = AutoLoad.ClassOnly('plugins.testlink.Attachment')
            attachmentProcesser = attachmentClass(content)
            testCase = attachmentProcesser.getProcessed()
            testCase['Vasi'] = tesId
            log.debug("+++++++++++++++++++++++++")
            log.debug(testCase)
            log.debug("+++++++++++++++++++++++++")
        except:
            print "Exception occured while processing Attachment"
            AutoLoad.logExceptionInfo()
        return testCase
            
    def _makeXmlRpcCall(self, methodName, data={}):
        result = "Unable to execute Function"
        data[self._devKeyName] = self._devKey
        try:
            log.debug("TestLink Signature used : " + self._testLinkSignature + " and Method : " + methodName)
            log.debug(" Data used : " + str(data))
            exec "result = self._server." + self._testLinkSignature + "." + methodName + "(data)"
        except Exception, v:
            log.critical("Exeception occured Unable to call TL" + str(v))
            log.critical("TestLink Signature used : " + self._testLinkSignature + " and Method : " + methodName)
            log.critical(" Data used : " + str(data))
            AutoLoad.logExceptionInfo(100)
        #print result
        return result
    '''
    Generic function to retrive the values from TestLink XMLRPC response
    '''
    def _idFinder(self, needle, listItems, nameKey="name", idKey="id"):
        foundId = False
        x = self._objectFinder(needle, listItems, nameKey)
        if x != 'Nothing Found in List':
            foundId = self._finder(x, idKey)
        else:
            log.warning('Error Occured Unable to find Id')
            log.warning('Tyring to find : ' + str(needle))
            log.warning('and Tag Value : ' + str(nameKey))
            log.warning('In Below List Items : ')
            log.warning(str(listItems))
        return foundId
    
    ''' 
    Searches a Key in the list Objects and returns the Object if the Key 
    is found in the object otherwise retuns a string
    '''
    def _objectFinder(self, needle, listItems, keyToUse="name"):
        foundObj = 'Nothing Found in List'
        for listKey in range(len(listItems)):
            try:
                tempName = listItems[listKey][keyToUse]
                if self._hasNeedle(tempName, needle):
                    foundObj = listItems[listKey]
            except KeyError:
                log.warning("Search Key not Found, Searched for : " + keyToUse)
        return foundObj
    
    def _hasNeedle(self, pstring, needle):
        if pstring.find(needle) >= 0:
            return True
        return False        
    
    def _finder(self, listItems, firstKey='' , secondKey=''):
        if firstKey == '':
            log.warning('Error Occured in Finder')
            log.warning("First key is blank Please Check ")
            log.warning("First key is blank Please Check ")
        if secondKey == '':
            return listItems[firstKey]
        return listItems[firstKey][secondKey]
    

        
